package model.mapping;

import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import view.panels.MapPanel;

import model.Model;
import model.Prueba;
import model.Model.Directions;
import model.info.Constants;
import model.info.Coordinate;

public class MapCheckouts {

	private Model model;
	
	public MapCheckouts(Model model) {
		
		this.model = model;
	}
	
	public int getDirection(int x,int y,int i,int j,Boolean action) {
		
		int resultado = -1;
		if (i > x && j > y)
			resultado = Model.Directions.RIGHTDOWN.ordinal();
		else if (i > x && j < y)
			resultado = Model.Directions.RIGHTUP.ordinal();
		else if (i < x && j > y)
			resultado = Model.Directions.LEFTDOWN.ordinal();
		else if (i < x && j < y)
			resultado = Model.Directions.LEFTUP.ordinal();
		else if (i == x && j > y)
			resultado = Model.Directions.DOWN.ordinal();
		else if (i == x && j < y)
			resultado = Model.Directions.UP.ordinal();
		else if (i > x && j == y)
			resultado = Model.Directions.RIGHT.ordinal();
		else if (i < x && j == y)
			resultado = Model.Directions.LEFT.ordinal();
		else if (x == i && y == j && action) {
			Point punto = new Point(x,y);
			model.getModelMapBuilder().getFreePoints().add(punto);
		}	
		return resultado;
	}
	
	public Boolean isRightLane(MapPoint point) {
		
		Boolean correct = false;
		for (int i=0;i<point.getDataList().size()&&!correct;i++) {
			if (point.getDataList().get(i).getLaneNumber().intValue() == 1)
				correct = true;
		}
	
		return correct;
	}

	public Point sharedDirection(MapPoint point1, MapPoint point2) {
		
		int x1 = point1.x;
		int y1 = point1.y;
		int x2 = point2.x;
		int y2 = point2.y;
		int agentDirection = getDirection(x1,y1,x2,y2,false);
		Boolean found = false;
		Point result = null;
		for (int i=0;i<point1.getDataList().size()&&!found;i++) {
			for (int j=0;j<point2.getDataList().size()&&!found;j++) {
				int direction1 = point1.getDataList().get(i).getDirection().intValue();
				int direction2 = point2.getDataList().get(j).getDirection().intValue();
				if (isSharing(agentDirection,direction1) && isSharing(agentDirection,direction2)
					&& isSharing(direction1,direction2)) {
					found = true;
					result = new Point(i,j);
				}
			}
		}
		return result;
	}
	
	public Boolean isSharingDirection(MapPoint point1, MapPoint point2) {
		
		int x1 = point1.x;
		int y1 = point1.y;
		int x2 = point2.x;
		int y2 = point2.y;
		int agentDirection = getDirection(x1,y1,x2,y2,false);
		Boolean found = false;
		for (int i=0;i<point1.getDataList().size()&&!found;i++) {
			for (int j=0;j<point2.getDataList().size()&&!found;j++) {
				int direction1 = point1.getDataList().get(i).getDirection().intValue();
				int direction2 = point2.getDataList().get(j).getDirection().intValue();
				if (isSharing(agentDirection,direction1) && isSharing(agentDirection,direction2)
					&& isSharing(direction1,direction2)) {
					found = true;
				}
			}
		}
		return found;
	}
	
	public int sharedDirection(int direction1, MapPoint point) {
		
		Boolean found = false;
		int result = -1;
		for (int i=0;i<point.getDataList().size()&&!found;i++) {
			int direction2 = point.getDataList().get(i).getDirection().intValue();
			if (isSharing(direction1,direction2)) {
				found = true;
				result = i;
			}
		}
		return result;
	}
	
	public Boolean isSharingDirection(int direction1, MapPoint point) {
		
		Boolean found = false;
		for (int i=0;i<point.getDataList().size()&&!found;i++) {
			int direction2 = point.getDataList().get(i).getDirection().intValue();
			if (isSharing(direction1,direction2)) {
				found = true;
			}
		}
		return found;
	}
	
	public boolean isSharing(int direction1, int direction2) {

		Boolean result = false;
		switch(direction1) {
			case 0:
				if (direction2 == Directions.UP.ordinal() || 
					direction2 == Directions.RIGHTUP.ordinal() ||
					direction2 == Directions.LEFTUP.ordinal() ||
					direction2 == Directions.RIGHT.ordinal() ||
					direction2 == Directions.LEFT.ordinal())	
						result = true;
				break;
			case 1:
				if (direction2 == Directions.DOWN.ordinal() || 
					direction2 == Directions.RIGHTDOWN.ordinal() ||
					direction2 == Directions.LEFTDOWN.ordinal() ||
					direction2 == Directions.RIGHT.ordinal() ||
					direction2 == Directions.LEFT.ordinal())	
						result = true;
				break;
			case 2:
				if (direction2 == Directions.RIGHT.ordinal() || 
					direction2 == Directions.RIGHTDOWN.ordinal() ||
					direction2 == Directions.RIGHTUP.ordinal() ||
					direction2 == Directions.UP.ordinal() ||
					direction2 == Directions.DOWN.ordinal())	
						result = true;
				break;
			case 3:
				if (direction2 == Directions.LEFT.ordinal() || 
					direction2 == Directions.LEFTUP.ordinal() ||
					direction2 == Directions.LEFTDOWN.ordinal() ||
					direction2 == Directions.UP.ordinal() ||
					direction2 == Directions.DOWN.ordinal())	
						result = true;
				break;
			case 4:
				if (direction2 == Directions.UP.ordinal() || 
					direction2 == Directions.RIGHT.ordinal() ||
					direction2 == Directions.RIGHTUP.ordinal() ||
					direction2 == Directions.LEFTUP.ordinal() ||
					direction2 == Directions.RIGHTDOWN.ordinal())	
						result = true;
				break;
			case 5:
				if (direction2 == Directions.UP.ordinal() || 
					direction2 == Directions.LEFT.ordinal() ||
					direction2 == Directions.LEFTUP.ordinal() ||
					direction2 == Directions.RIGHTUP.ordinal() ||
					direction2 == Directions.LEFTDOWN.ordinal())	
						result = true;
				break;
			case 6:
				if (direction2 == Directions.DOWN.ordinal() || 
					direction2 == Directions.RIGHT.ordinal() ||
					direction2 == Directions.RIGHTDOWN.ordinal() ||
					direction2 == Directions.LEFTDOWN.ordinal() ||
					direction2 == Directions.RIGHTUP.ordinal())	
						result = true;
				break;
			case 7:
				if (direction2 == Directions.DOWN.ordinal() || 
					direction2 == Directions.LEFT.ordinal() ||
					direction2 == Directions.LEFTDOWN.ordinal() ||
					direction2 == Directions.RIGHTDOWN.ordinal() ||
					direction2 == Directions.LEFTUP.ordinal())	
						result = true;
				break;
		}
		return result;
	}
	
	public Boolean isSharingId(MapPoint point1,MapPoint point2) {
		
		Boolean result = false;
		for (int i=0;i<point1.getDataList().size()&&!result;i++)
			for (int j=0;j<point2.getDataList().size()&&!result;j++) {
				String id1 = point1.getDataList().get(i).getId();
				String id2 = point2.getDataList().get(j).getId();
				if (id1.equals(id2))
					result = true;
			}
		return result;
	}
	
	public Boolean isSamePlace(int x,int y,int i,int j) {
		
		if (i != x || j != y)
			return false;
		return true;
	}
	
	public Point oppositedDirection(MapPoint point1,MapPoint point2) {
		
		Boolean opposite = false;
		Point result = null;
		for (int i=0;i<point1.getDataList().size()&&!opposite;i++)
			for (int j=0;j<point2.getDataList().size()&&!opposite;j++) {
				int direction1 = point1.getDataList().get(i).getDirection().intValue();
				int direction2 = point2.getDataList().get(j).getDirection().intValue();
				if (isOppositeDirection(direction1,direction2)) {
					opposite = true;
					result = new Point(i,j);
				}
			}
		return result;
	}
	
	public Boolean isAceptableDirection(int direction1,MapPoint point) {
		
		Boolean aceptable = false;
		for (int i=0;i<point.getDataList().size()&&!aceptable;i++) {
			int direction2 = point.getDataList().get(i).getDirection().intValue();
				if (!isOppositeDirection(direction1,direction2)) {
					aceptable = true;
				}
			}
		return aceptable;
	}
	
	public Boolean isOppositeDirection(MapPoint point1,MapPoint point2) {
		
		Boolean opposite = false;
		for (int i=0;i<point1.getDataList().size()&&!opposite;i++)
			for (int j=0;j<point2.getDataList().size()&&!opposite;j++) {
				int direction1 = point1.getDataList().get(i).getDirection().intValue();
				int direction2 = point2.getDataList().get(j).getDirection().intValue();
				if (isOppositeDirection(direction1,direction2)) {
					opposite = true;
				}
			}
		return opposite;
	}
	
	
	public boolean isOppositeDirection(int actualDirection,int nextDirection) {
		
		Boolean opposite = false;
		switch (actualDirection) {
			case 0:
				if (nextDirection == Directions.DOWN.ordinal())
					opposite = true;
				break;
			case 1:
				if (nextDirection == Directions.UP.ordinal())
					opposite = true;
				break;
			case 2:
				if (nextDirection == Directions.LEFT.ordinal())
					opposite = true;
				break;
			case 3:
				if (nextDirection == Directions.RIGHT.ordinal())
					opposite = true;
				break;
			case 4:
				if (nextDirection == Directions.LEFTDOWN.ordinal())
					opposite = true;
				break;
			case 5:
				if (nextDirection == Directions.RIGHTDOWN.ordinal())
					opposite = true;
				break;
			case 6:
				if (nextDirection == Directions.LEFTUP.ordinal())
					opposite = true;
				break;
			case 7:
				if (nextDirection == Directions.RIGHTUP.ordinal())
					opposite = true;
				break;
		}
		return opposite;
	}	
	
	public Integer getOpposedDirection(Integer sentido) {
		
		Integer resultado = -1;
		switch(sentido) {
			case 0:
				resultado = Model.Directions.UP.ordinal();
				break;
			case 1:
				resultado = Model.Directions.DOWN.ordinal();
				break;
			case 2:
				resultado = Model.Directions.LEFT.ordinal();
				break;
			case 3:
				resultado = Model.Directions.RIGHT.ordinal();
				break;
			case 4:
				resultado = Model.Directions.LEFTDOWN.ordinal();
				break;
			case 5:
				resultado = Model.Directions.RIGHTDOWN.ordinal();
				break;
			case 6:
				resultado = Model.Directions.LEFTUP.ordinal();
				break;
			case 7:
				resultado = Model.Directions.RIGHTUP.ordinal();
				break;
		}
		return resultado;
	}
	
	public MapPoint getNextPoint(MapPoint point1,MapPoint point2) {
		
		int x = point1.x;
		int y = point1.y;
		int i = point2.x;
		int j = point2.y;
		MapPoint resultado = null;
		MapPoint[][] driverMap = model.getModelMapBuilder().getDriverMap();
		if ((i > x && j > y) && (isInMap(i+1,j+1)))
			resultado = driverMap[i+1][j+1];
		else if ((i > x && j < y) && (isInMap(i+1,j-1)))
			resultado = driverMap[i+1][j-1];
		else if ((i < x && j > y) && (isInMap(i-1,j+1)))
			resultado = driverMap[i-1][j+1];
		else if ((i < x && j < y) && (isInMap(i-1,j-1)))
			resultado = driverMap[i-1][j-1];
		else if ((i == x && j > y) && (isInMap(i,j+1)))
			resultado = driverMap[i][j+1];
		else if ((i == x && j < y)&& (isInMap(i,j-1)))
			resultado = driverMap[i][j-1];
		else if ((i > x && j == y) && (isInMap(i+1,j)))
			resultado = driverMap[i+1][j];
		else if ((i < x && j == y) && (isInMap(i-1,j)))
			resultado = driverMap[i-1][j];
		
		return resultado;
	}
	
	public Boolean isInMap(int x,int y) {
		
		MapPanel mapaPanel = model.getMapPanel();
		Boolean correct = false;
		if (x < mapaPanel.getWidth() && x >= 0 && y < mapaPanel.getHeight() && y >= 0)
			correct = true;
		return correct;
	}
	
	public Boolean isInMap(Coordinate coordinate) {
		
		Boolean correct = false;
		Point point = getPointFromCoordinate(coordinate);
		if (model.getMapCheckouts().isInMap(point.x,point.y))
			correct = true;
		return correct;
	}
	
	public Boolean isVehicleWay(int x,int y,int i) {
		
		MapPoint[][] driverMap = model.getModelMapBuilder().getDriverMap();
		Boolean correcto = false;
		if (!driverMap[x][y].getDataList().get(i).getType().equals(Constants.PATH) &&
			!driverMap[x][y].getDataList().get(i).getType().equals(Constants.PEDESTRIAN) &&
			!driverMap[x][y].getDataList().get(i).getType().equals(Constants.STEPS) &&
			!driverMap[x][y].getDataList().get(i).getType().equals(Constants.FOOTWAY) &&
			!driverMap[x][y].getDataList().get(i).getType().equals(Constants.CYCLEWAY))
			correcto = true;
		return correcto;	
	}
	
	public Boolean isVehicleWay(String valor) {
		
		Boolean correcto = false;
		if (!valor.equals(Constants.PATH) && !valor.equals(Constants.PEDESTRIAN)
			&& !valor.equals(Constants.STEPS) && !valor.equals(Constants.FOOTWAY)
			&& !valor.equals(Constants.CYCLEWAY))
			correcto = true;
		return correcto;
	}
	
	public Point getPointFromCoordinate(Coordinate coordinate) {
		
		int x = MapPanel.lon2position(coordinate.getLongitude(),model.getMapPanel().getZoom());
		int y = MapPanel.lat2position(coordinate.getLatitude(),model.getMapPanel().getZoom());
		Point position = model.getMapPanel().getMapPosition();
		x = x - position.x;
		y = y - position.y;
		Point result = new Point(x,y);
		return result;
	}
	
	public MapPoint getAccuratePointFromCoordinate(Coordinate coordinate) {
		
		MapPoint point = null;
		Double minDistance = Constants.GREATEST_VALUE_DOUBLE;
		for (int i=0;i<model.getMapPanel().getWidth();i++)
			for (int j=0;j<model.getMapPanel().getHeight();j++) {
				if (model.getModelMapBuilder().getDriverMap()[i][j].isRoad()) {
					Double newDistance = model.getModelMapBuilder().getDriverMap()[i][j].getCoordinate().getDistance(coordinate);
					if (newDistance < minDistance) {
						minDistance = newDistance;
						point = model.getModelMapBuilder().getDriverMap()[i][j];
					}
				}
			}	
		return point;
	}
	
	public int getCorrectCrossingPart(MapPoint point) {
		
		int result = 0;
		int x = point.x;
		int y = point.y;
		ArrayList<String> ids = new ArrayList<String>();
		ArrayList<Integer> lanes = new ArrayList<Integer>();
		int[] count = new int[point.getDataList().size()];
		for (int l=0;l<point.getDataList().size();l++) {
			count[l] = 0;
			ids.add(point.getDataList().get(l).getId());
			lanes.add(point.getDataList().get(l).getLaneNumber());
		}
		for (int i=x-1;i<x+1;i++) {
			for (int j=y-1;j<y+1;j++) {
				if (isInMap(i,j) && !isSamePlace(x,y,i,j) && 
					model.getModelMapBuilder().getDriverMap()[i][j].isRoad()) {
					MapPoint candidate = model.getModelMapBuilder().getDriverMap()[i][j];
					for (int l=0;l<candidate.getDataList().size();l++) {
						int idIndex = ids.indexOf(candidate.getDataList().get(l).getId());
						if (idIndex >= 0) {
							int lane = lanes.get(idIndex);
							if (candidate.getDataList().get(l).getLaneNumber().intValue() == lane) {
								count[idIndex] = count[idIndex] + 1;
							}
						}
					}
				}
			}
		}	
		int pos = 0;
		int min = count[pos];
		for (int i=1;i<count.length;i++) {
			if (count[i] < min) {
				pos = i;
				min = count[i];
			}
		}	
		String minId = ids.get(pos);
		Boolean found = false;
		for (int i=0;i<point.getDataList().size()&&!found;i++) {
				if (point.getDataList().get(i).getId().equals(minId)) {
					result = i;
					found = true;
				}
		}
		return result;
	}
	
	public boolean hasMoreThanOnePointPerLayerZero(MapPoint point) {

		Boolean result = false;
		int value = 0;
		for (int i=0;i<point.getDataList().size();i++) 
			if (point.getDataList().get(i).getLayer().intValue() == 0)
				value = value + 1;
		if (value > 1)
			result = true;
		return result;
	}
	
	public MapPoint getClosestPoint(MapPoint point,int position) {
		
		MapPoint result = null;
		return result;
	}
	
	public int getLayerZeroPosition(MapPoint point) {
		
		Boolean found = false;
		int position = 0;
		for (int i=0;i<point.getDataList().size()&&!found;i++) {
			if (point.getDataList().get(i).getLayer().intValue() == 0) {
				found = true;
				position = i;
			}
		}
		return position;
	}
	
	// Comprobaciones
	
	public void comprobacion(BufferedImage buffer) {
		
		MapPanel mapaPanel = model.getMapPanel();
		for(int i=0;i<mapaPanel.getWidth();i++)
			for (int j=0;j<mapaPanel.getHeight();j++) {
				if ((buffer.getRGB(i,j) == Color.white.getRGB()) && !model.getModelMapBuilder().getDriverMap()[i][j].isRoad()) {
					//puntos.add(new Point(i,j));
					System.out.println("Punto: "+i+","+j);
				}
			}
	}
	
	public void pruebaDeFuncionamiento(MapPoint[][] mapa,BufferedImage buffer) {
		
		//Prueba de funcionamiento del modelo.
		comprobacion(buffer);
		int k=0;
		BufferedImage bufferFinal = new BufferedImage(buffer.getWidth(),buffer.getHeight(),BufferedImage.TYPE_INT_RGB);
		for (int i=0;i<buffer.getWidth();i++) 
			for (int j=0;j<buffer.getHeight();j++) 
				if (mapa[i][j].isRoad()) {
					if (mapa[i][j].getDataList().get(k).getDirection().equals(0))
						bufferFinal.setRGB(i,j,new Color(0,0,255).getRGB());
					else if (mapa[i][j].getDataList().get(k).getDirection().equals(1))
						bufferFinal.setRGB(i,j,new Color(Color.gray.getRGB()).getRGB());
					else if (mapa[i][j].getDataList().get(k).getDirection().equals(2))
						bufferFinal.setRGB(i,j,new Color(0,255,0).getRGB());
					else if (mapa[i][j].getDataList().get(k).getDirection().equals(3))
						bufferFinal.setRGB(i,j,new Color(Color.orange.getRGB()).getRGB());
					else if (mapa[i][j].getDataList().get(k).getDirection().equals(4))
						bufferFinal.setRGB(i,j,new Color(255,0,0).getRGB());
					else if (mapa[i][j].getDataList().get(k).getDirection().equals(5))
						bufferFinal.setRGB(i,j,new Color(Color.cyan.getRGB()).getRGB());
					else if (mapa[i][j].getDataList().get(k).getDirection().equals(6))
						bufferFinal.setRGB(i,j,new Color(Color.PINK.getRGB()).getRGB());
					else if (mapa[i][j].getDataList().get(k).getDirection().equals(7))
						bufferFinal.setRGB(i,j,new Color(Color.yellow.getRGB()).getRGB());
					else
						bufferFinal.setRGB(i,j,new Color(255,255,255).getRGB());
				}
				else
					bufferFinal.setRGB(i,j,new Color(0,0,0).getRGB());
					/*if (mapa[i][j].getDataList().size() > 1)
						bufferFinal.setRGB(i,j,new Color(0,255,0).getRGB());
					else
						bufferFinal.setRGB(i,j,new Color(255,255,255).getRGB());
						/*if (mapa[i][j].getOcupante().equals(Individuals.Vehiculo.ordinal())) {
							System.out.println(mapa[i][j].getDataList().size()+" "+i+","+j);
							bufferFinal.setRGB(i,j,new Color(0,255,0).getRGB());
						}*/
					//if (!mapa[i][j].getDataList().get(k).getOneway()) {
						
					///else
							//bufferFinal.setRGB(i,j,new Color(255,255,255).getRGB());
					//}
		
		/*Coordinate c1 = null;
		try {
			c1 = new Coordinate(40.44855,-3.72899);
		} catch (CoordinateRangeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		double distance = 9999999;
		int x = -1;
		int y = -1;
		for (int i=0;i<buffer.getWidth();i++) 
			for (int j=0;j<buffer.getHeight();j++) {
				if (mapa[i][j].getVia()) {
					if (distance > mapa[i][j].getCoordinate().getDistance(c1)) {
						distance =  mapa[i][j].getCoordinate().getDistance(c1);
						x = i;
						y = j;
					}
				}
			}
		System.out.println(mapa[x][y].getCoordinate());
		System.out.println("X: "+x+" ,Y: "+y);
		bufferFinal.setRGB(x,y,new Color(255,0,0).getRGB());*/
			
		Prueba p3 = new Prueba(bufferFinal);
	}
}
